package com.zhou.app.favourite.security.remember;

import com.zhou.app.favourite.util.ServletUtil;
import org.springframework.security.web.authentication.rememberme.InvalidCookieException;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.util.StringUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;

/**
 * 弥补原生的JdbcTokenRepositoryImpl 改为删除token只删除当前无效的用户自己的token
 *
 * createPersistentRememberMeServices createTokenBasedRememberMeServices
 *
 * @author xianfeng
 * @date 2023/5/14 14:39
 */
public class MyJdbcTokenRepositoryImpl extends JdbcTokenRepositoryImpl {

    private String cookieName;

    public static final String DEF_REMOVE_USER_TOKENS_SQL = "delete from persistent_logins where series = ?";

    @Override
    public void removeUserTokens(String username) {
        HttpServletRequest request = ServletUtil.getRequest();
        String rememberMeCookie = extractRememberMeCookie(request);
        if (rememberMeCookie == null) {
            return;
        }
        this.logger.debug("Remember-me cookie detected");
        if (rememberMeCookie.length() == 0) {
            this.logger.debug("Cookie was empty");
            return;
        }
        String[] cookieTokens = decodeCookie(rememberMeCookie);
        if (cookieTokens.length != 2) {
            this.logger.debug("Cookie token did not contain " + 2 + " tokens, but contained '"
                    + Arrays.asList(cookieTokens) + "'");
            return;
        }
        String presentedSeries = cookieTokens[0];
        String presentedToken = cookieTokens[1];
        getJdbcTemplate().update(DEF_REMOVE_USER_TOKENS_SQL, presentedSeries);
    }

    //todo 模拟老的repository，修改删除时获取当前用户的rememberMe删除，其他的用户不做处理
    protected String[] decodeCookie(String cookieValue) throws InvalidCookieException {
        for (int j = 0; j < cookieValue.length() % 4; j++) {
            cookieValue = cookieValue + "=";
        }
        try {
            Base64.getDecoder().decode(cookieValue.getBytes());
        } catch (IllegalArgumentException ex) {
            throw new InvalidCookieException("Cookie token was not Base64 encoded; value was '" + cookieValue + "'");
        }
        String cookieAsPlainText = new String(Base64.getDecoder().decode(cookieValue.getBytes()));
        String[] tokens = StringUtils.delimitedListToStringArray(cookieAsPlainText, ":");
        for (int i = 0; i < tokens.length; i++) {
            try {
                tokens[i] = URLDecoder.decode(tokens[i], StandardCharsets.UTF_8.toString());
            } catch (UnsupportedEncodingException ex) {
                this.logger.error(ex.getMessage(), ex);
            }
        }
        return tokens;
    }

    protected String extractRememberMeCookie(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if ((cookies == null) || (cookies.length == 0)) {
            return null;
        }
        for (Cookie cookie : cookies) {
            if (this.cookieName.equals(cookie.getName())) {
                return cookie.getValue();
            }
        }
        return null;
    }


    public void setCookieName(String cookieName) {
        this.cookieName = cookieName;
    }
}
